package com.hzy.friend.utils;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.MatchOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
/***
 * @author huangzhaoyong
 * @desc mongodb查询参数拼接
 * @date  2018/12/20 0020 上午 9:46
 */
public class MongoDBUtils<T> {
    /**
     * 拼接查询参数，不拼接transientAnno注解的参数
     * @param t
     * @param <T>
     * @return
     */
    public static<T> Query getQueryByParams(T t) {
        Query query = new Query();
        if(null == t){
            return query;
        }
        // 搜索时间
        AtomicReference<Long> searchStartTime = new AtomicReference<>();
        AtomicReference<Long> searchEndTime = new AtomicReference<>();
        // 属性遍历
        List<Field> fieldList = FieldUtils.getAllFieldsList(t.getClass());
        fieldList.forEach(field -> {
            try {
                //打开私有访问
                field.setAccessible(true);
                //获取属性
                String name = field.getName();
                if(null == field.get(t)){
                    return;
                }
                Object value = field.get(t);
                if(null == value || StringUtils.isBlank(value.toString())){
                    return;
                }
                //静态属性
                if(Modifier.isStatic(field.getModifiers())){
                    return;
                }
                //排除serialVersionUID
                if(StringUtils.equals(name, "serialVersionUID")){
                    return;
                }
                //主键
                boolean idAnno = field.isAnnotationPresent(Id.class);
                if(idAnno){
                    query.addCriteria(Criteria.where("_id").is(value));
                    return;
                }
                //transientAnno 注解的不自动添加
                boolean transientAnno = field.isAnnotationPresent(Transient.class);
                if(transientAnno) {
                    //加入时间搜索组装
                    // searchStartTime,searchEndTime
                    if (StringUtils.equals(name, "searchEndTime") ) {
                        searchEndTime.set((Long) value);
                    }
                    if (StringUtils.equals(name, "searchStartTime")) {
                        searchStartTime.set((Long) value);
                    }
                    // 过滤条件集合
                    if(value instanceof List){
                        // 字段集合过滤：字段source，集合名称：sourceList
                        name = name.replace("List", "").replace("list", "");
                        if(StringUtils.isBlank(name)){
                            return;
                        }
                        Field declaredField = FieldUtils.getDeclaredField(t.getClass(), name, true);
                        if(null != declaredField){
                            List listValue = (List) value;
                            if(null == listValue || listValue.size() < 1){
                                return;
                            }
                            query.addCriteria(Criteria.where(name).in((List)value));
                        }
                    }
                    return;
                }
                query.addCriteria(Criteria.where(name).is(value));
            } catch (Exception e){
                e.printStackTrace();
            }
        });
        //时间搜索
        setSearchTime(query, searchStartTime.get(), searchEndTime.get());
        return query;
    }

    /**
     * 搜索时间判断
     * @param query
     * @param searchStartTime
     * @param searchEndTime
     */
    public static void setSearchTime(Query query, Long searchStartTime, Long searchEndTime){
        if (null == searchStartTime && null == searchEndTime){
            return;
        }

        if (null != searchStartTime && null != searchEndTime){
            query.addCriteria(Criteria.where("createTime")
                    .lte(searchEndTime)
                    .gte(searchStartTime));
            return;
        }

        if (null != searchStartTime){
            query.addCriteria(Criteria.where("createTime").gte(searchStartTime));
            return;
        }

        if (null != searchEndTime){
            query.addCriteria(Criteria.where("createTime").lte(searchEndTime));
            return;
        }
    }

    /**
     * 修改参数拼接，不拼主键和transientAnno注解的属性
     * @param t
     * @param <T>
     * @return
     */
    public static<T> Update getUpdateParams(T t) {
        Update update = new Update();
        List<Field> fieldList = FieldUtils.getAllFieldsList(t.getClass());
        fieldList.forEach(field -> {
            try {
                //打开私有访问
                field.setAccessible(true);
                //获取属性
                String name = field.getName();
                if(null == field.get(t)){
                    return;
                }
                Object value = field.get(t);
                if(null == value || StringUtils.isBlank(value.toString())){
                    return;
                }
                //主键不添加
                boolean idAnno = field.isAnnotationPresent(Id.class);
                if(idAnno){
                    return;
                }
                //transientAnno 注解的不自动添加
                boolean transientAnno = field.isAnnotationPresent(Transient.class);
                if(transientAnno){
                    return;
                }
                update.set(name, value);
            } catch (Exception e){
                e.printStackTrace();
            }
        });
        return update;
    }

    /**
     * 聚合组装 MatchOperation 参数
     * @param params
     * @return
     */
    public static MatchOperation getMatchOperation(Map<String, Object> params) {
        if(null == params || params.size() < 1){
            return Aggregation.match(new Criteria());
        }
        // 组装参数
        Criteria criteria = null;
        Iterator<String> iterator = params.keySet().iterator();
        while (iterator.hasNext()){
            String key = iterator.next();
            if (StringUtils.equals(key, "searchEndTime") || StringUtils.equals(key, "searchStartTime")) {
                continue;
            }
            Object value = params.get(key);
            if(null == value){
                continue;
            }
            Criteria param;
            if(value instanceof List){
                param = Criteria.where(key).in((List)params.get(key));
            } else {
                param = Criteria.where(key).is(params.get(key));
            }
            // 组装到参数中
            if(null == criteria){
                criteria = param;
            }else{
                criteria.andOperator(param);
            }
        }
        return Aggregation.match(setSearchTime(criteria, params.get("searchEndTime"), params.get("searchStartTime")));
    }

    /**
     * 搜索时间判断
     * @param criteria
     * @param searchStartTime
     * @param searchEndTime
     */
    public static Criteria setSearchTime(Criteria criteria, Object searchStartTime, Object searchEndTime){
        if(null == criteria){
            return new Criteria();
        }
        if (null != searchStartTime && null != searchEndTime){
            criteria.andOperator(Criteria.where("createTime")
                    .lte(searchEndTime)
                    .gte(searchStartTime));
        }else if (null != searchStartTime){
            criteria.andOperator(Criteria.where("createTime").gte(searchStartTime));
        }else if (null != searchEndTime){
            criteria.andOperator(Criteria.where("createTime").lte(searchEndTime));
        }
        return criteria;
    }
}

